package com.aop;

import com.exception.CrmebException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

@Slf4j
@Aspect
@Component
public class LimitIPRequestDisplay {

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;
    // 限制访问次数
    private static final int limit = 10;

    @Pointcut("execution(* com.zbkj.crmeb.front.controller.*.*(..))")
    public void before() {
    }

    @Before("before()")
    public void requestLimit(JoinPoint joinPoint) throws CrmebException {
        // 获取HttpRequest
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();

        // 判断request不能为空
        if (request == null) {
            throw new CrmebException("HttpServletRequest有误...");
        }

        String ip = request.getRemoteAddr();
        String uri = request.getRequestURI();
        String redisKey = "limit-ip-request:" + uri + ":" + ip;
        // 设置在redis中的缓存，累加1
        long count = redisTemplate.opsForValue().increment(redisKey, 1);

        // 如果该key不存在，则从0开始计算，并且当count为1的时候，设置过期时间1分钟
        if (count == 1) {
            redisTemplate.expire(redisKey, 60, TimeUnit.SECONDS);
        }

        // 如果redis中的count大于限制的次数，则报错
        if (count > limit) {
            log.info("用户IP[" + ip + "]访问地址[" + uri + "]超过了限定的次数[" + limit + "]");
            throw new CrmebException("访问频繁，请稍后重试...");
        }
    }
}
